package genedit.model.graph;

import genedit.controller.CommandManager;
import genedit.gui.GMainFrame;
import genedit.gui.GProjectTree;
import genedit.model.HierarchyElement;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import javax.swing.SwingUtilities;
import javax.swing.tree.TreeNode;

/**
 * Klasa za dijagrame. Sadrži listu grafičkih elemenata, kao i potrebne metode
 * za njihovu obradu.
 * 
 * @author Nikola
 * @version 1.2 18/12/13
 */
public class GraphDocument extends genedit.model.Document {

	private static final long serialVersionUID = 1L;

	/**
	 * Lista grafičkih elemenata.
	 */
	private List<GraphElement> elements;

	/**
	 * Referenca na klasu zaduženu za obradu komandi, uključujući i undo/redo
	 * operacije.
	 */
	private transient CommandManager invoker;

	private List<GraphElement> selectedElements;

	public GraphDocument(HierarchyElement parent) {
		super(parent);
		invoker = new CommandManager();
	}

	public GraphDocument(HierarchyElement parent, String name) {
		super(parent, name);
		invoker = new CommandManager();
	}

	public List<GraphElement> getElements() {
		if (elements == null)
			elements = new java.util.ArrayList<GraphElement>();
		return elements;
	}

	public java.util.Iterator<GraphElement> getIteratorElements() {
		if (elements == null)
			elements = new java.util.ArrayList<GraphElement>();
		return elements.iterator();
	}

	public void setElements(java.util.Collection<GraphElement> newElements) {
		removeAllElements();
		for (java.util.Iterator<GraphElement> iter = newElements.iterator(); iter.hasNext();)
			addElements((GraphElement) iter.next());
	}

	public void addElements(GraphElement newGraphElement) {
		if (newGraphElement == null)
			return;
		if (this.elements == null)
			this.elements = new java.util.ArrayList<GraphElement>();
		if (!this.elements.contains(newGraphElement))
			this.elements.add(newGraphElement);

		// Statička metoda updateComponentTreeUI ažurira prikaz stabla
		// hijerarhije
		SwingUtilities.updateComponentTreeUI(GProjectTree.getInstance().getTree());
		getObservable().setChanged();
		getObservable().notifyObservers();
	}

	public void removeElements(GraphElement oldGraphElement) {
		if (oldGraphElement == null)
			return;
		if (this.elements != null)
			if (this.elements.contains(oldGraphElement))
				this.elements.remove(oldGraphElement);
		SwingUtilities.updateComponentTreeUI(GProjectTree.getInstance().getTree());
		getObservable().setChanged();
		getObservable().notifyObservers();
	}

	public void removeAllElements() {
		if (elements != null)
			elements.clear();
		SwingUtilities.updateComponentTreeUI(GProjectTree.getInstance().getTree());
	}

	public CommandManager getInvoker() {
		if (invoker == null)
			invoker = new CommandManager();
		return invoker;
	}

	public void setInvoker(CommandManager newCommandManager) {
		this.invoker = newCommandManager;
	}

	public List<GraphElement> getSelectedElements() {
		if (selectedElements == null)
			selectedElements = new java.util.ArrayList<GraphElement>();
		return selectedElements;
	}

	public java.util.Iterator<GraphElement> getIteratorSelectedElements() {
		if (selectedElements == null)
			selectedElements = new java.util.ArrayList<GraphElement>();
		return selectedElements.iterator();
	}

	public void setSelectedElements(java.util.Collection<GraphElement> newElements) {
		removeAllElements();
		for (java.util.Iterator<GraphElement> iter = newElements.iterator(); iter.hasNext();)
			addSelectedElements((GraphElement) iter.next());
	}

	public void addSelectedElements(GraphElement newGraphElement) {
		if (newGraphElement == null)
			return;
		if (this.selectedElements == null)
			this.selectedElements = new java.util.ArrayList<GraphElement>();
		if (!this.selectedElements.contains(newGraphElement))
			this.selectedElements.add(newGraphElement);

		GProjectTree.getInstance().setSelectionFromCanvas();
		getObservable().setChanged();
		getObservable().notifyObservers();
	}

	public void addSelectedElementsFromTree(GraphElement newGraphElement) {
		if (newGraphElement == null)
			return;
		if (this.selectedElements == null)
			this.selectedElements = new java.util.ArrayList<GraphElement>();
		if (!this.selectedElements.contains(newGraphElement))
			this.selectedElements.add(newGraphElement);

		getObservable().setChanged();
		getObservable().notifyObservers();
	}

	public void removeSelectedElements(GraphElement oldGraphElement) {
		if (oldGraphElement == null)
			return;
		if (this.selectedElements != null)
			if (this.selectedElements.contains(oldGraphElement))
				this.selectedElements.remove(oldGraphElement);
		// SwingUtilities.updateComponentTreeUI(GProjectTree.getInstance().getTree());
		GProjectTree.getInstance().setSelectionFromCanvas();
		getObservable().setChanged();
		getObservable().notifyObservers();
	}

	public void removeAllSelectedElements() {
		if (selectedElements != null)
			selectedElements.clear();
		// SwingUtilities.updateComponentTreeUI(GProjectTree.getInstance().getTree());
		GProjectTree.getInstance().setSelectionFromCanvas();
	}

	public void rename(String name) {
		this.name = name;
		if (GMainFrame.getInstance().contains(this))
			GMainFrame.getInstance().changeTitle(this);
	}

	/**
	 * Metoda za osvežavanje prikaza datog dijagrama.
	 */
	public void refresh() {
		getObservable().setChanged();
		getObservable().notifyObservers();
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Enumeration children() {
		List<Object> subdocumentsAndElements = new ArrayList<Object>();
		subdocumentsAndElements.addAll(getSubDocument());
		subdocumentsAndElements.addAll(getElements());
		return Collections.enumeration(subdocumentsAndElements);
	}

	@Override
	public TreeNode getChildAt(int childIndex) {
		List<TreeNode> subdocumentsAndElements = new ArrayList<TreeNode>();
		subdocumentsAndElements.addAll(getSubDocument());
		subdocumentsAndElements.addAll(getElements());
		return subdocumentsAndElements.get(childIndex);
	}

	@Override
	public int getChildCount() {
		List<TreeNode> subdocumentsAndElements = new ArrayList<TreeNode>();
		subdocumentsAndElements.addAll(getSubDocument());
		subdocumentsAndElements.addAll(getElements());
		return subdocumentsAndElements.size();
	}

	@Override
	public int getIndex(TreeNode node) {
		List<TreeNode> subdocumentsAndElements = new ArrayList<TreeNode>();
		subdocumentsAndElements.addAll(getSubDocument());
		subdocumentsAndElements.addAll(getElements());
		return subdocumentsAndElements.indexOf(node);
	}
}